#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import allure
from pylenium.driver import PyleniumShould
from pylenium.element import ElementShould,ElementsShould
from dragon.locatordetail import LocatorDetail
from pylenium.log import logger
from utils import strings
from selenium.common.exceptions import StaleElementReferenceException

class DraPyleniumShould:
    def __init__(self,should:PyleniumShould,pyd):
        from dragon.drapylenium import DraPylenium
        self._should=should
        self._pyd:DraPylenium=pyd

    def contain_title(self,title: str):
        stepText = f'断言：当前页面标题应该包含【{title}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.contain_title(title)
        return self._pyd

    def contain_url(self,url: str):
        stepText = f'断言：当前页面url应该包含【{url}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.contain_url(url)
        return self._pyd

    def have_title(self,title: str):
        stepText = f'断言：当前页面标题应该为【{title}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_title(title)
        return self._pyd

    def have_url(self,url: str):
        stepText = f'断言：当前页面url应该为【{url}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_url(url)
        return self._pyd

    def not_find(self,ld: LocatorDetail):
        stepText = f'断言：当前页面应该不存在【{ld.name}】'
        with allure.step(stepText):
            logger.info(stepText)
            if ld.type == 'css':
                self._should.not_find(ld.locator)
                return self._pyd
            elif ld.type == 'xpath':
                self._should.not_findx(ld.locator)
                return self._pyd
            elif ld.type == 'text':
                self._should.not_contain(ld.locator)
                return self._pyd
            else:
                raise ValueError('元素type必须是`css`、`xpath`、`text`其中之一')

class DraElementShould:
    def __init__(self, should:ElementShould,draElement):
        from dragon.element import DraElement
        self._draElement:DraElement=draElement
        self._ld=self._draElement._ld
        self._should=should

    def be_checked(self):
        stepText = f'断言：【{self._ld.name}】应该勾选'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_checked()
        return self._draElement

    def be_clickable(self):
        stepText = f'断言：【{self._ld.name}】应该可点击'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_clickable()
        return self._draElement

    def be_enabled(self):
        stepText = f'断言：【{self._ld.name}】应该可用'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_enabled()
        return self._draElement

    def be_disabled(self):
        stepText = f'断言：【{self._ld.name}】应该不可用'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_disabled()
        return self._draElement

    def be_focused(self):
        stepText = f'断言：【{self._ld.name}】应该聚焦'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_focused()
        return self._draElement

    def not_be_focused(self):
        stepText = f'断言：【{self._ld.name}】应该不聚焦'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.not_be_focused()
        return self._draElement

    def contain_text(self,text: str, case_sensitive:bool=True):
        stepText = f'断言：【{self._ld.name}】应该包含【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.contain_text(text,case_sensitive)
        return self._draElement

    def have_text(self,text: str, case_sensitive:bool=False):
        stepText = f'断言：【{self._ld.name}】应该等于【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_text(text,case_sensitive)
        return self._draElement

    def not_have_text(self,text: str, case_sensitive:bool=True):
        stepText = f'断言：【{self._ld.name}】应该不等于【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.not_have_text(text,case_sensitive)
        return self._draElement

    def not_contain_text(self,text:str,case_sensitive:bool=True):
        eleText=self._draElement.text
        if not case_sensitive:
            eleText=eleText.lower()
            text=text.upper()
        stepText = f'断言：【{self._ld.name}】应该不包含【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            assert text not in eleText, f'【{self._ld.name}】：【{eleText}】包含【{text}】'

    def disappear(self):
        stepText = f'断言：【{self._ld.name}】应该消失'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.disappear()
        return self._draElement

    def have_attr(self, attr: str, value: str):
        stepText = f'断言：【{self._ld.name}】应该拥有属性【{attr}】且等于【{value}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_attr(attr,value)
        return self._draElement

    def not_have_attr(self, attr: str, value: str):
        stepText = f'断言：【{self._ld.name}】应该不拥有属性【{attr}】或不等于【{value}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.not_have_attr(attr,value)
        return self._draElement

    def have_class(self,class_name: str):
        stepText = f'断言：【{self._ld.name}】应该拥有`class`属性且等于【{class_name}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_class(class_name)
        return self._draElement

    def have_prop(self, prop: str, value: str):
        stepText = f'断言：【{self._ld.name}】应该拥有属性【{prop}】且等于【{value}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_prop(prop,value)
        return self._draElement

    def have_value(self,value):
        stepText = f'断言：【{self._ld.name}】应该拥有`value`且等于【{value}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_value(value)
        return self._draElement

    def not_have_value(self,value):
        stepText = f'断言：【{self._ld.name}】应该没有`value`属性或不等于【{value}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.not_have_value(value)
        return self._draElement

    def be_visible(self):
        stepText = f'断言：【{self._ld.name}】应该可见'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_visible()
        return self._draElement
    def be_hidden(self):
        stepText = f'断言：【{self._ld.name}】应该隐藏'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_hidden()
        return self._draElement

    def be_selected(self):
        stepText = f'断言：【{self._ld.name}】应该选中'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_selected()
        return self._draElement

    def reload(self):
        stepText = f'断言：【{self._ld.name}】应该已刷新'
        with allure.step(stepText):
            logger.info(stepText)
            try:
                self._draElement._element.text()
            except StaleElementReferenceException:
                assert 1 == 1
            else:
                assert 1 == 2,f'【{self._ld.name}】没有刷新'
        return self._draElement

    def not_reload(self):
        stepText = f'断言：【{self._ld.name}】应该没有刷新'
        with allure.step(stepText):
            logger.info(stepText)
            try:
                self._draElement._element.text()
            except StaleElementReferenceException:
                assert 1 == 2
            else:
                assert 1 == 1,f'【{self._ld.name}】已刷新'
        return self._draElement

    def have_location(self,location:dict):
        stepText = f'断言：【{self._ld.name}】的位置应该为：【{location}】'
        with allure.step(stepText):
            logger.info(stepText)
            assert self._draElement.location == location, f'【{self._ld.name}】的位置【{self._draElement.location}】!=【{location}】'
        return self._draElement

class DraElementsShould:
    def __init__(self, should: ElementsShould,draElements):
        from dragon.element import DraElements
        self._should=should
        self._draElements:DraElements=draElements
        self._ld=self._draElements._ld

    def be_empty(self):
        stepText = f'断言：【{self._ld.name}】数量应该为0'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_empty()
        return self._draElements

    def not_be_empty(self):
        stepText = f'断言：【{self._ld.name}】数量应该大于0'
        with allure.step(stepText):
            self._should.not_be_empty()
            logger.info(stepText)
        return self._draElements

    def have_length(self, length: int):
        stepText = f'断言：【{self._ld.name}】数量应该为【{length}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.have_length(length)
        return self._draElements

    def have_length_greater_than(self,length: int):
        stepText = f'断言:【{self._ld.name}】数量应该大于【{length}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_greater_than(length)
        return self._draElements

    def have_length_less_than(self, length: int):
        stepText = f'断言:【{self._ld.name}】数量应该小于【{length}】'
        with allure.step(stepText):
            logger.info(stepText)
            self._should.be_less_than(length)
        return self._draElements

    def be_in_range(self,minValue,maxValue,dateTimeStr:bool=False):
        '''断言：所有值应该都在minValue和maxValue之间'''
        self._should.not_be_empty()
        elements = self._draElements._elements
        if dateTimeStr:
            numberList = [e.text() for e in elements]
        else:
            numberList = [strings.extract_number(e.text()) for e in elements]
        stepText = f'断言：【{self._ld.name}】应该在【{minValue}~{maxValue}】之间'
        with allure.step(stepText):
            logger.info(stepText)
            assert max(numberList) <= maxValue, f'【{self._ld.name}】不在【{minValue}~{maxValue}】之间'
            assert min(numberList) >= minValue, f'【{self._ld.name}】不在【{minValue}~{maxValue}】之间'
        return self._draElements

    def be_asc(self,dateTimeStr:bool=False):
        '''
        断言：应该升序排列

        :param dateTimeStr: bool，是否是时间字符串
        :return: None
        '''
        self._should.not_be_empty()
        elements = self._draElements._elements
        if dateTimeStr:
            numberList = [e.text() for e in elements]
        else:
            numberList = [strings.extract_number(e.text()) for e in elements]
        stepText = f'断言：【{self._ld.name}】应该是升序排列'
        with allure.step(stepText):
            logger.info(stepText)
            # 应该升序排列
            assert numberList==sorted(numberList),f'【{self._ld.name}】不是升序排序'
        return self._draElements

    def be_desc(self,dateTimeStr=False):
        '''
        断言：应该降序排列

        :param dateTimeStr: bool，是否是时间字符串
        :return: None
        '''
        self._should.not_be_empty()
        elements=self._draElements._elements
        if dateTimeStr:
            numberList = [e.text() for e in elements]
        else:
            numberList = [strings.extract_number(e.text()) for e in elements]
        stepText = f'断言：【{self._ld.name}】应该是降序排列'
        with allure.step(stepText):
            logger.info(stepText)
            # 应该降序排列
            assert numberList==sorted(numberList,reverse=True),f'【{self._ld.name}】不是降序排序'
        return self._draElements

    def all_contain_text(self,text:str,case_sensitive:bool=True):
        '''
        断言：所有元素应该包含text

        :param text: str
        :return:
        '''
        self._should.not_be_empty()
        elements=self._draElements._elements
        stepText = f'断言：【{self._ld.name}】应该全部包含【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            for e in elements:
                eleText=e.text()
                if not case_sensitive:
                    eleText = eleText.lower()
                    text = text.lower()
                assert text in eleText, f'【{eleText}】不包含【{text}】'
        return self._draElements

    def all_have_text(self,text:str,case_sensitive:bool=True):
        '''
        断言：所有元素应该等于text

        :param text: str
        :return:
        '''
        self._should.not_be_empty()
        elements = self._draElements._elements
        stepText = f'断言：【{self._ld.name}】应该全部等于【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            for e in elements:
                eleText = e.text()
                if not case_sensitive:
                    eleText = eleText.lower()
                    text = text.lower()
                assert eleText == text, f'【{eleText}】不等于【{text}】'
        return self._draElements

    def all_not_have_text(self,text:str,case_sensitive:bool=True):
        '''
        断言：所有元素应该等于text

        :param text: str
        :return:
        '''
        self._should.not_be_empty()
        elements = self._draElements._elements
        stepText = f'断言：【{self._ld.name}】应该全部都不等于【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            for e in elements:
                eleText = e.text()
                if not case_sensitive:
                    eleText = eleText.lower()
                    text = text.lower()
                assert eleText != text, f'【{eleText}】等于【{text}】'
        return self._draElements

    def all_not_contain_text(self,text:str,case_sensitive:bool=True):
        '''
        断言：所有元素应该包含text

        :param text: str
        :return:
        '''
        self._should.not_be_empty()
        elements=self._draElements._elements
        stepText = f'断言：【{self._ld.name}】应该全部都不包含【{text}】'
        with allure.step(stepText):
            logger.info(stepText)
            for e in elements:
                eleText = e.text()
                if not case_sensitive:
                    eleText = eleText.lower()
                    text = text.lower()
                assert text not in eleText, f'【{eleText}】包含【{text}】'
        return self._draElements